<?php if ( ! defined('BASEPATH')) exit('This file does not run directly. Sorry.'); ?>
<?php
/**
 * Kalaisoo.
 *
 * A lightweight no-framework framework written in PHP.
 *
 * @package Kalaisoo
 * @author $Author: info@sah-company.com $
 * @version $Id: report.php 144 2012-01-25 14:36:44Z info@sah-company.com $
 */

/**
 * Load dependencies.
 */
Registry::instance()->loader->model(array(
	'report_column',
	'report_filter',
	'report_orderfield'
	)
);

/**
 * Kalaisoo Report Model Class.
 *
 * @package Kalaisoo
 * @subpackage Model
 * @author $Author: info@sah-company.com $
 */
class Model_Report extends Model
{
	/**
	 * __construct.
	 */
	public function construct()
	{
		parent::__construct();
	}
	
	/**
	 * returns the tags of a bean.
	 *
	 * @return array
	 */
	public function getTags() {
		return array(
			$this->bean->name
		);
	}
	
	/**
	 * returns an array with special actions the model can take.
	 *
	 * @return array
	 */
	public function actions()
	{
		//if ( ! $this->bean->getId()) return array();
		return array(
			'run' => true
		);
	}
	
	/**
	 * analyzes the bean, creates a mysql view and queries that view with report criterias.
	 *
	 * a mysql view is built after the report bean type and named report*.
	 * this is report is then queried with the reports criterias.
	 *
	 * @todo is catching the exception enough?
	 * @todo implement IN operator which needs stacking ? or a real string with PDO
	 * @return void
	 */
	public function run()
	{
		$this->describe($this->bean->model, 'report'.$this->bean->model);
		//Registry::instance()->loader->language($this->tables());
		$this->controller()->addBreadcrumbs('run');
		$this->controller()->toolbarActions('run', array('index'));
		$this->controller()->data['rows'] = array();
		$this->controller()->data['urlToOpenPattern'] = '{language}/editor/view/'.$this->bean->model.'/%s';
		Model::$sortField = 'sequence';
		Model::$sortDirection = 'asc';
		$columns = $this->bean->ownReport_column;
		$filters = $this->bean->ownReport_filter;
		$orders = $this->bean->ownReport_orderfield;
		usort($columns, array('Model', 'sort'));
		usort($filters, array('Model', 'sort'));
		usort($orders, array('Model', 'sort'));
		$c = array(
			$this->bean->model.'_id'
		);
		$f = array();
		$v = array();
		$o = array();
		$w = array(); // width of fields
		foreach ($columns as $n=>$column) {
			$c[] = $column->attribute;
			$w[$column->attribute] = $column->width;
		}
		$this->controller()->data['columns'] = $c;
		$this->controller()->data['widths'] = $w;
		$fmap = array(
			'cn' => 'like ?',
			'eq' => '= ?',
			'neq' => '!= ?',
			'gt' => '> ?',
			'gte' => '>= ?',
			'lt' => '< ?',
			'lte' => '<= ?',
			//'in' => 'IN (?)',
			'bw' => 'like ?',
			'ew' => 'like ?',
			'isnull' => 'IS NULL',
			'notnull' => 'IS NOT NULL'
		);
		foreach ($filters as $n=>$filter) {
			$f[] = $filter->attribute.' '.$fmap[$filter->operator].' '.$filter->logic;
			switch ($filter->operator) {
				case 'cn':
					$value = '%'.$filter->value.'%';
					break;
				case 'bw':
					$value = $filter->value.'%';
					break;
				case 'ew':
					$value = '%'.$filter->value;
					break;
				default:
					$value = $filter->value;
			}
			$v[] = $value;
		}
		foreach ($orders as $n=>$order) {
			$o[] = $order->attribute.' '.$order->direction;
		}
		$ctext = implode(', ', $c);
		$ftext = implode(' ', $f);
		$otext = implode(', ', $o);
		$gtext = $this->bean->model.'_id';
		$sql_cmd = 'SELECT %s FROM %s WHERE %s GROUP BY %s ORDER BY %s';
		$sql = sprintf($sql_cmd, $ctext, 'report'.$this->bean->model, $ftext, $gtext, $otext);
		try {
			$this->controller()->data['rows'] = R::getAll($sql, $v);
			//$this->controller()->data['messages'][] = $sql;
		} catch (Exception $e) {
			$this->controller()->data['errors'][] = __('report_run_failed');
			//$this->controller()->data['errors'][] = $sql;
		}
		return $this->controller()->template->view('report/table', $this->controller()->data);
	}
	
	/**
	 * loads the array $this->gestalt of this bean for use with Model::gestalt().
	 *
	 * if the model for the report is set, the bean gets analyzed by Model::describe().
	 * watch out that the Registry is used to pass the options for some fields to subaltern
	 * beans of the report bean. Beware and clean this up.
	 *
	 * @todo Do not pass option values via the Registry!
	 */
	public function loadGestalten()
	{
		$this->gestalt['default'] = array(
			array(
				'type' => 'text',
				'name' => 'name',
				'parameters' => array(
					'required' => 'required'
				)
			),
			array(
				'type' => 'text',
				'name' => 'model',
				'parameters' => array(
					'required' => 'required'
				)
			),
			array(
				'type' => 'textarea',
				'name' => 'description'
			)
		);
		// if we have a model here, user can add columns and so on
		if ($this->bean->getId() && $this->bean->model) {
			$this->describe($this->bean->model); // but do not build a mysql view
			$myFields = array();
			foreach ($this->fields() as $column=>$alias) {
				if (substr($alias, -3, 3) == '_id') continue;
				$myFields[$alias] = __($alias.'_label');
			}
			$_SESSION['options_fieldnames_for_report'] = $myFields; // super-ugly
			$this->gestalt['default'][] = array(
				'type' => 'own',
				'name' => 'report_column',
				'parameters' => array(
					'sort' => array(
						'name' => 'sequence',
						'direction' => 'asc'
					)
				)
			);
			$this->gestalt['default'][] = array(
				'type' => 'own',
				'name' => 'report_filter',
				'parameters' => array(
					'sort' => array(
						'name' => 'sequence',
						'direction' => 'asc'
					)
				)
			);
			$this->gestalt['default'][] = array(
				'type' => 'own',
				'name' => 'report_orderfield',
				'parameters' => array(
					'sort' => array(
						'name' => 'sequence',
						'direction' => 'asc'
					)
				)
			);
		}
	}
	
	/**
	 * validates the data and returns either true or false.
	 *
	 * @return bool
	 */
	public function validate()
	{
		$valid = true;
		return $valid;
	}
	
	/**
	 * open.
	 */
	public function open()
	{
	}

	/**
	 * dispense.
	 */
	public function dispense()
	{
	}

	/**
	 * update.
	 */
	public function update()
	{
	}
	
	/**
	 * after_update.
	 */
	public function after_update()
	{
	}
	
	/**
	 * delete.
	 */
	public function delete()
	{
	}
	
	/**
	 * after_delete.
	 */
	public function after_delete()
	{
	}
}
?>